#!/usr/bin/env python
# Prototype code for IRC based Z80 assembler

import os
import urllib2
import tempfile
import subprocess
import shutil, glob

import z80core_dict

# Get variables from dict!
ASSEMBLER_OPTCMD = z80core_dict.get_assembler_defs()
ONLINE_PASTEBIN_LOOKUP = z80core_dict.get_pastebin()

global GID
GID = 0

# Functions
def stop():
	#raw_input()
	blabla = 1
	
def assembler_dict(asm):
	for assembler in ASSEMBLER_OPTCMD:
		if assembler[0] == asm:
			return assembler[2]

def get_assembler_type(asm):
	for assembler in ASSEMBLER_OPTCMD:
		if assembler[0] == asm:
			return assembler[1]

def convert_bin(binfile, target):
	printl("Command:")
	printl(str(("./wabbitsign "+binfile+" "+target).split(" ")))
	printl("./wabbitsign "+binfile+" "+target)
	CONV_PROC = subprocess.Popen(("./wabbitsign "+binfile+" "+target).split(" "), shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
	
	#print str(("wine wabbit.exe "+binfile+" "+target).split(" "))
	#print "wine wabbit.exe "+binfile+" "+target
	#CONV_PROC = subprocess.Popen(("wine wabbit.exe "+binfile+" "+target).split(" "), shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

	CONV_OUTPUT = CONV_PROC.stdout.read()
	CONV_ERRCODE = CONV_PROC.wait()
	printl("Output:")
	printl(CONV_OUTPUT)
	printl("Error code: "+str(CONV_ERRCODE))
	return CONV_ERRCODE

def printl(thestr=""):
	global GID, ASMPROJDIR
	print "[Job "+str(GID)+"] "+thestr
	try:
		fh_log = open(os.path.join(ASMPROJDIR, "asmlog.txt"), "a")
		fh_log.write(thestr+"\n")
		fh_log.close()
	except IOError,e:
		print "ERROR: Couldn't write to log file! Reason: "+str(e)

def compile_file(id, prgm, src, target):
	global GID, ASMPROJDIR
	FAIL_CODE = 0
	GID = 0
	GID = id
	ASSEMBLER = prgm
	TARGET_FILE = target
	ONLINE_SOURCE = src
	
	OLD_DIR = os.getcwd()
	
	# Options: brass, spasm, tasm
	#ASSEMBLER="spasm"
	#ASSEMBLER="brass"
	
	# Target file
	#TARGET_FILE="test.8xp"
	
	# Source location online (pastebins only)
	#ACTUAL_ONLINE_SOURCE="http://cemetech.pastebin.com/raw.php?i=Zm3jM4eR"
	#ONLINE_SOURCE="http://cemetech.pastebin.com/FiUtAgBw"
	#ONLINE_SOURCE="http://cemetech.pastebin.com/nKD16037"
	
	# Figure out online source
	
	# First, let's check which profile to choose.
	
	# Build another array from ONLINE_PASTEBIN_LOOKUP, sans "@@ONLINE_ID@@".
	#ONLINE_PASTEBIN_LOOKUP_NOREP = []
	#for SITEARRAY in ONLINE_PASTEBIN_LOOKUP:
	#	IDARRAY = []
	#	for ID in SITEARRAY:
	#		NEWID = ID.replace("@@ONLINE_ID@@", "")
	#		IDARRAY.append(NEWID)
	#	ONLINE_PASTEBIN_LOOKUP_NOREP.append(IDARRAY)
	
	ASMPROJDIR = tempfile.mkdtemp("", "asmproj_")
	
	# OK, let's actually find it.
	FINAL_PICK = ""
	FINAL_PICK_INDEX = 0
	#for SITEARRAY in ONLINE_PASTEBIN_LOOKUP_NOREP:
	for SITEARRAY in ONLINE_PASTEBIN_LOOKUP:
		printl("Searching for string "+SITEARRAY[0]+" in URL...")
		if ONLINE_SOURCE.find(SITEARRAY[0]) != -1:
			FINAL_PICK = SITEARRAY[0]
			break
		FINAL_PICK_INDEX = FINAL_PICK_INDEX + 1
	
	printl("Found string "+FINAL_PICK+" in URL...")
	stop()
	
	# Now take the index and look up the definition.
	DEF_SPLIT = ONLINE_PASTEBIN_LOOKUP[FINAL_PICK_INDEX][1].split("@@ONLINE_ID@@")
	if len(DEF_SPLIT) == 2:
		if DEF_SPLIT[0] == "":
			# The online ID is at the beginning
			ONLINE_ID = ONLINE_SOURCE[7:ONLINE_SOURCE.find(ONLINE_PASTEBIN_LOOKUP[FINAL_PICK_INDEX][0])]
		else:
			# The online ID is at the end
			ONLINE_ID = ONLINE_SOURCE[ONLINE_SOURCE.find(ONLINE_PASTEBIN_LOOKUP[FINAL_PICK_INDEX][0])+len(ONLINE_PASTEBIN_LOOKUP[FINAL_PICK_INDEX][0]):]
	elif len(DEF_SPLIT) == 3:
		ONLINE_ID = ONLINE_SOURCE[len(DEF_SPLIT[0]):][:ONLINE_SOURCE[len(DEF_SPLIT[0]):].find(DEF_SPLIT[2])]
		
	# WOW... that was intense stuff. Let's see if everything came out OK...
	printl("Final online ID: "+ONLINE_ID)
	stop()
	
	# Not too bad, eh? Let's go ahead and get the final URL! :D
	FINAL_URL = ONLINE_PASTEBIN_LOOKUP[FINAL_PICK_INDEX][2].replace("@@ONLINE_ID@@", ONLINE_ID)
	printl("Final URL: "+FINAL_URL)
	stop()
	
	# Grab online source!
	try:
		#ASMPROJDIR = tempfile.mkdtemp("", "asmproj_")
		ASMFILEN = tempfile.mkstemp(".asm", "tmp", ASMPROJDIR)[1]
		ASMFILE = open(ASMFILEN, "w")
		grabconn = urllib2.urlopen(FINAL_URL)
		ASMFILE.write(grabconn.read())
		grabconn.close()
		ASMFILE.close()
	except urllib2.HTTPError, e:
		printl("ERROR: Couldn't get the file! Blame it on HTTP Error Code "+str(e.code)+"! :P")
		#exit(1)
		FAIL_CODE = 1
		return [FAIL_CODE, ASMPROJDIR]
	except urllib2.URLError, e:
		printl("ERROR: Cannot retrieve URL: " + str(e.reason[1]))
		#exit(1)
		FAIL_CODE = 1
		return [FAIL_CODE, ASMPROJDIR]
	
	printl("Saved ASM file to: "+ASMFILEN)
	stop()
	
	# Great! Now we need to parse the other fun options - building ones, in particular.
	
	# Build the command!
	CMD = ""
	
	CMD_SET = assembler_dict(ASSEMBLER)
	
	# Sanity checks!
	CHECKPATH = ASMPROJDIR + "/" + TARGET_FILE
	if os.path.abspath(CHECKPATH) != CHECKPATH:
		print "Hacking attempt!"
		print "Typed path is "+CHECKPATH
		print "Absolute path is "+os.path.abspath(CHECKPATH)
		printl("Invalid file name!")
		#exit(1)
		FAIL_CODE = 1
		return [FAIL_CODE, ASMPROJDIR]
	
	BIN_FILE = TARGET_FILE[:len(TARGET_FILE)-4]+".bin"
	for command in CMD_SET:
		CMD = CMD + command.replace("!!SOURCE!!", ASMFILEN).replace("!!TARGET_FILE!!", os.path.join(ASMPROJDIR, TARGET_FILE)).replace("!!BIN_FILE!!", os.path.join(ASMPROJDIR, BIN_FILE)) + " "
	
	printl("Final assembling command: "+CMD)
	stop()
	
	# Copy all necessary headers to the temp dir
	printl("Copying necessary headers...")
	for thefile in os.listdir('asmincludes/'):
		if thefile.endswith(".inc"):
			try:
				printl("Copying "+'asmincludes/'+thefile+" to "+ASMPROJDIR+"...")
				shutil.copy('asmincludes/'+thefile, ASMPROJDIR)
			except IOError,e:
				printl("ERROR: Header file couldn't be copied! Reason: "+str(e))
				FAIL_CODE = 1
	stop()
	printl("Copying any needed assembler binaries...")
	printl("Copying wabbitsign to "+ASMPROJDIR+"...")
	shutil.copy('wabbitsign', ASMPROJDIR)
	printl("Copying Brass.exe to "+ASMPROJDIR+"...")
	shutil.copy('Brass.exe', ASMPROJDIR)
	printl("Copying wabbit.exe to "+ASMPROJDIR+"...")
	shutil.copy('wabbit.exe', ASMPROJDIR)
	printl("Copying Tasm.exe to "+ASMPROJDIR+"...")
	shutil.copy('Tasm.exe', ASMPROJDIR)
	
	# Execute the command!
	printl("Running command...")
	os.chdir(ASMPROJDIR)
	ASM_PROC = subprocess.Popen(CMD.split(" ")[:len(CMD.split(" "))-1], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
	ASM_OUTPUT = ASM_PROC.stdout.read()
	ASM_ERRCODE = ASM_PROC.wait()
	printl("Output:")
	printl(ASM_OUTPUT)
	printl("Error code: "+str(ASM_ERRCODE))
	stop()

	if (ASM_ERRCODE != 0):
		FAIL_CODE = 1
	######################################
	# WIP - continue later!!!!
	#FINAL_NAME_VAR = TARGET_FILE.upper().
	
	printl("Assembler type: "+str(get_assembler_type(ASSEMBLER)))
	
	ECODE=0
	if TARGET_FILE.lower().endswith(".bin"):
		# We're done!
		printl("That's all! :D")
	elif TARGET_FILE.lower().endswith(".8xk"):
		# Check what compiler we're using, and its profile.
		if get_assembler_type(ASSEMBLER) == "bin":
			# We need to take the bin file and convert it to 8Xk app.
			ECODE = convert_bin(os.path.join(ASMPROJDIR, BIN_FILE), os.path.join(ASMPROJDIR, TARGET_FILE))
			FAIL_CODE = ECODE
		elif get_assembler_type(ASSEMBLER) == "any":
			# Ignore, we're already done!
			printl("That's all! :D")
		else:
			# Corrupt entry!
			printl("OMG Oh noes! Terrifying evil monsterous error! O_O")
			printl("The assembler type is invalid or corrupt.")
			printl("Allowed types are 'bin' and 'any'.")
			printl("This is a rare error, and is usually caused by the person managing")
			printl("this, not you. So report it! :)")
			FAIL_CODE = 1
			#exit(1)
	elif TARGET_FILE.lower().endswith(".8xp"):
		# Check what compiler we're using, and its profile.
		if get_assembler_type(ASSEMBLER) == "bin":
			# We need to take the bin file and convert it to 8xp program.
			ECODE = convert_bin(os.path.join(ASMPROJDIR, BIN_FILE), TARGET_FILE)
		elif get_assembler_type(ASSEMBLER) == "any":
			# Ignore, we're already done!
			printl("That's all! :D")
		else:
			# Corrupt entry!
			printl("OMG Oh noes! Terrifying evil monsterous error! O_O")
			printl("The assembler type is invalid or corrupt.")
			printl("Allowed types are 'bin' and 'any'.")
			printl("This is a rare error, and is usually caused by the person managing")
			printl("this, not you. So report it! :)")
			FAIL_CODE = 1
			#exit(1)
	elif TARGET_FILE.lower().endswith(".83p"):
		# Check what compiler we're using, and its profile.
		if get_assembler_type(ASSEMBLER) == "bin":
			# We need to take the bin file and convert it to 83p program.
			ECODE = convert_bin(os.path.join(ASMPROJDIR, BIN_FILE), os.path.join(ASMPROJDIR, TARGET_FILE))
		elif get_assembler_type(ASSEMBLER) == "any":
			# Ignore, we're already done!
			printl("That's all! :D")
		else:
			# Corrupt entry!
			printl("OMG Oh noes! Terrifying evil monsterous error! O_O")
			printl("The assembler type is invalid or corrupt.")
			printl("Allowed types are 'bin' and 'any'.")
			printl("This is a rare error, and is usually caused by the person managing")
			printl("this, not you. So report it! :)")
			#exit(1)
	else:
		printl("Unknown (or unsupported) file extension! :(")
		FAIL_CODE = 1
	
	stop()
	
	os.chdir(OLD_DIR)
	
	if ECODE != 0:
		FAIL_CODE = 1
		
	printl("FAIL_CODE is "+str(FAIL_CODE))
	return [FAIL_CODE, ASMPROJDIR, os.path.join(ASMPROJDIR, TARGET_FILE), os.path.join(ASMPROJDIR, BIN_FILE)]
	# Done! Remove temp files...
	#printl("Cleaning up...")
	#shutil.rmtree(ASMPROJDIR)
	#stop()
	
